package com.ybox.crawler.config;

import com.ybox.crawler.domain.core.callback.DataValidateCallBack;
import com.ybox.crawler.domain.core.callback.ProxyProviderCallBack;
import com.ybox.crawler.domain.core.parse.ParseRule;
import com.ybox.crawler.domain.core.proxy.CrawlerProxy;
import com.ybox.crawler.domain.core.proxy.CrawlerProxyProvider;
import com.ybox.crawler.domain.enums.CrawlerEnum;
import com.ybox.crawler.domain.pojos.ClIpPool;
import com.ybox.crawler.helper.CookieHelper;
import com.ybox.crawler.helper.CrawlerHelper;
import com.ybox.crawler.process.entity.CrawlerConfigProperty;
import com.ybox.crawler.service.CrawlerIpPoolService;
import com.ybox.crawler.utils.SeleniumClient;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import us.codecraft.webmagic.Spider;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 16554
 */
@Getter
@Setter
@Configuration
public class CrawlerConfig {

    @Value("${webdriver.chrome.driver}")
    private String driver;

    /**
     * csdn 初始url前缀
     */
    @Value("${crawler.csdn.init.prefix}")
    private String csdnPrefix;// https://www.csdn.net/nav/

    /**
     * csdn初始url后缀
     */
    @Value("${crawler.csdn.init.suffix}")
    private String csdnSuffix;// java,web,arch,db,mobile,ops,sec

    /**
     * cookieName
     */
    @Value("${crawler.csdn.crux.cookie.name}")
    private String CRUX_COOKIE_NAME;

    /**
     * 是否使用代理IP
     */
    @Value("${proxy.isUsedProxyIp}")
    private Boolean isUsedProxyIp;

    /**
     * 下次更新时间
     */
    @Value("${crawler.help.nextPagingSize}")
    private Integer crawlerHelpNextPagingSize;



    /**
     * 获取初始的CSDNurl
     *
     * @return
     */
    public List<String> getInitCsdnUrlList() {
        List<String> initCrawlerUrlList = new ArrayList<>();
        if (StringUtils.isNotEmpty(csdnSuffix)) {
            String[] urlArray = csdnSuffix.split(",");
            if (urlArray != null && urlArray.length > 0) {
                for (int i = 0; i < urlArray.length; i++) {
                    String initUrl = urlArray[i];
                    if (StringUtils.isNotEmpty(initUrl)) {
                        if (!initUrl.toLowerCase().startsWith("http")) {
                            initCrawlerUrlList.add(csdnPrefix + initUrl);
                        }
                    }
                }
            }
        }
        return initCrawlerUrlList;
    }

    /**
     * 获取初始的Juejinurl
     *
     * @return
     */
    public List<String> getInitJuejinUrlList() {
        List<String> initCrawlerUrlList = new ArrayList<>();
        if (StringUtils.isNotEmpty(csdnSuffix)) {
            String[] urlArray = csdnSuffix.split(",");
            if (urlArray != null && urlArray.length > 0) {
                for (int i = 0; i < urlArray.length; i++) {
                    String initUrl = urlArray[i];
                    if (StringUtils.isNotEmpty(initUrl)) {
                        if (!initUrl.toLowerCase().startsWith("http")) {
                            initCrawlerUrlList.add(csdnPrefix + initUrl);
                        }
                    }
                }
            }
        }
        return initCrawlerUrlList;
    }

    @Bean
    public SeleniumClient getSeleniumClient() {
        SeleniumClient.setDriver(driver);
        return new SeleniumClient();
    }

    /**
     * 设置Cookie辅助类
     *
     * @return CookieHelper
     */
    @Bean
    public CookieHelper getCookieHelper() {
        return new CookieHelper(CRUX_COOKIE_NAME);
    }

    /**
     * 数据校验匿名内部类
     *
     * @param cookieHelper cookieHelper
     * @return DataValidateCallBack
     */
    private DataValidateCallBack getDataValidateCallBack(CookieHelper cookieHelper) {
        return new DataValidateCallBack() {
            @Override
            public boolean validate(String content) {
                boolean flag = true;
                if (StringUtils.isEmpty(content)) {
                    flag = false;
                } else {
                    boolean isContains_acw_sc_v2 = content.contains("acw_sc__v2");
                    boolean isContains_location_reload = content.contains("document.location.reload()");
                    if (isContains_acw_sc_v2 && isContains_location_reload) {
                        flag = false;
                    }
                }
                return flag;
            }
        };
    }


    /**
     * CrawerHelper 辅助类
     *
     * @return
     */
    @Bean
    public CrawlerHelper getCrawerHelper() {
        CookieHelper cookieHelper = getCookieHelper();
        CrawlerHelper crawerHelper = new CrawlerHelper();
        DataValidateCallBack dataValidateCallBack = getDataValidateCallBack(cookieHelper);
        crawerHelper.setDataValidateCallBack(dataValidateCallBack);
        return crawerHelper;
    }

    /**
     * CrawlerProxyProvider bean
     *
     * @return
     */
    @Bean
    public CrawlerProxyProvider getCrawlerProxyProvider() {
        CrawlerProxyProvider crawlerProxyProvider = new CrawlerProxyProvider();
        crawlerProxyProvider.setUsedProxyIp(isUsedProxyIp);
        // 设置动态代理
        crawlerProxyProvider.setProxyProviderCallBack(new ProxyProviderCallBack() {
            @Override
            public List<CrawlerProxy> getProxyList() {
                return getCrawlerProxyList();
            }

            @Override
            public void unavilable(CrawlerProxy crawlerProxy) {
                unavilableProxy(crawlerProxy);
            }
        });
        return crawlerProxyProvider;
    }

    @Autowired
    private CrawlerIpPoolService crawlerIpPoolService;

    /**
     * 获取初始化的ip列表
     *
     * @return
     */
    public List<CrawlerProxy> getCrawlerProxyList() {
        List<CrawlerProxy> crawlerProxyList = new ArrayList<>();
        ClIpPool clIpPool = new ClIpPool();
        clIpPool.setDuration(5);
        List<ClIpPool> clIpPools = crawlerIpPoolService.queryAvailabelList(clIpPool);
        if (null != clIpPools && !clIpPools.isEmpty()) {
            for (ClIpPool ipPool : clIpPools) {
                crawlerProxyList.add(new CrawlerProxy(ipPool.getIp(), ipPool.getPort()));
            }
        }

        return crawlerProxyList;
    }

    /**
     * 代理ip不可用处理方法
     *
     * @param crawlerProxy
     */
    public void unavilableProxy(CrawlerProxy crawlerProxy) {
        if (crawlerProxy != null) {
            crawlerIpPoolService.unAvailabelProxy(crawlerProxy, "自动禁用");
        }
    }

    public Map<String, String> getXpath(CrawlerEnum.CrawlerType type) {
        Map<String, String> result = new HashMap<>();
        if (type == CrawlerEnum.CrawlerType.CSDN){
            result.put("initCrawlerXpath", "//div[@class='Community']/div[@class='active-blog']//div[@class='content']//div[@class='operation-c']/a");
            result.put("helpCrawlerXpath", "//div[@class='mainContent']//article[@class='blog-list-box']/a");
        }
        else if (type == CrawlerEnum.CrawlerType.JUEJIN){
            result.put("initCrawlerXpath", "");
            result.put("helpCrawlerXpath", "");
        }
        else if (type == CrawlerEnum.CrawlerType.WEIXIN){
            result.put("initCrawlerXpath", "");
            result.put("helpCrawlerXpath", "");
        }
        else if (type == CrawlerEnum.CrawlerType.ZHIHU){
            result.put("initCrawlerXpath", "");
            result.put("helpCrawlerXpath", "");
        }
        return result;
    }

    @Bean
    public CrawlerConfigProperty getCsdnConfigProperty() {
        Map<String, String> xpath = getXpath(CrawlerEnum.CrawlerType.CSDN);
        CrawlerConfigProperty property = new CrawlerConfigProperty();
        // 初始化url列表
        property.setInitCrawlerUrlList(getInitCsdnUrlList());
        // 初始化url解析规则定义
        property.setInitCrawlerXpath(xpath.get("initCrawlerXpath"));
        // 用户空间下的解析规则  url
        property.setHelpCrawlerXpath(xpath.get("helpCrawlerXpath"));
        // 抓取用户空间下的页大小
        property.setCrawlerHelpNextPagingSize(getCrawlerHelpNextPagingSize());
        // 目标页的解析规则
        property.setTargetParseRuleList(getCsdnTargetParseRuleList());
        return property;
    }


    /**
     * CSDN 目标页的解析规则
     *
     * @return
     */
    private List<ParseRule> getCsdnTargetParseRuleList() {
        List<ParseRule> parseRules = new ArrayList<ParseRule>() {{
            // 标题
            add(new ParseRule("title", CrawlerEnum.ParseRuleType.XPATH, "//h1[@class='title-article']/text()"));
            // 作者
            add(new ParseRule("author", CrawlerEnum.ParseRuleType.XPATH, "//a[@class='follow-nickName ']/text()"));
            // 发布日期
            add(new ParseRule("releaseDate", CrawlerEnum.ParseRuleType.XPATH, "//div[@class='bar-content']/span[@class='time']/text()"));
            // 标签
            add(new ParseRule("labels", CrawlerEnum.ParseRuleType.XPATH, "//div[@class='tags-box artic-tag-box']/a/text()"));
            // 个人空间
            add(new ParseRule("personalSpace", CrawlerEnum.ParseRuleType.XPATH, "//a[@class='follow-nickName ']/@href"));
            // 阅读量
            add(new ParseRule("readCount", CrawlerEnum.ParseRuleType.XPATH, "//span[@class='read-count']/text()"));
            // 点赞量
            add(new ParseRule("likes", CrawlerEnum.ParseRuleType.XPATH, "//div[@class='toolbox-middle']/ul[@class='toolbox-list']/li[@class='tool-item tool-item-size tool-active is-like']/a/span/text()"));
            // 回复次数
            add(new ParseRule("commentCount", CrawlerEnum.ParseRuleType.XPATH, "//div[@class='toolbox-middle']/ul[@class='toolbox-list']/li[@class='tool-item tool-item-size tool-active tool-item-comment']/a/span/text()"));
            // 文章内容
            add(new ParseRule("content", CrawlerEnum.ParseRuleType.XPATH, "//div[@id='article_content']/html()"));
        }};
        return parseRules;
    }


    @Bean
    public CrawlerConfigProperty getJuejinConfigProperty() {
        Map<String, String> xpath = getXpath(CrawlerEnum.CrawlerType.JUEJIN);
        CrawlerConfigProperty property = new CrawlerConfigProperty();
        // 初始化url列表
        property.setInitCrawlerUrlList(getInitJuejinUrlList());
        // 初始化url解析规则定义
        property.setInitCrawlerXpath(xpath.get("initCrawlerXpath"));
        // 用户空间下的解析规则  url
        property.setHelpCrawlerXpath(xpath.get("helpCrawlerXpath"));
        // 抓取用户空间下的页大小
        property.setCrawlerHelpNextPagingSize(getCrawlerHelpNextPagingSize());
        // 目标页的解析规则
        property.setTargetParseRuleList(getJuejinTargetParseRuleList());
        return property;
    }


    /**
     * JUEJIN 目标页的解析规则
     *
     * @return
     */
    private List<ParseRule> getJuejinTargetParseRuleList() {
        List<ParseRule> parseRules = new ArrayList<ParseRule>() {{
            // 标题
            add(new ParseRule("title", CrawlerEnum.ParseRuleType.XPATH, "//article[@class='article']/h1[@class='article-title']/text()"));
            // 作者
            add(new ParseRule("author", CrawlerEnum.ParseRuleType.XPATH, "//article[@class='article']/div[@class='author-info-block']//div[@class='author-name']//span[@class='name']/text()"));
            // 发布日期
            add(new ParseRule("releaseDate", CrawlerEnum.ParseRuleType.XPATH, "//article[@class='article']/div[@class='author-info-block']//div[@class='meta-box']/time[@class='time']/text()"));
            // 标签
            add(new ParseRule("labels", CrawlerEnum.ParseRuleType.XPATH, "//div[@class='tag-list-container']/a/span//text()"));
            // 个人空间
            add(new ParseRule("personalSpace", CrawlerEnum.ParseRuleType.XPATH, "//div[@class='author-info-block']/a/@href"));
            // 阅读量
            add(new ParseRule("readCount", CrawlerEnum.ParseRuleType.XPATH, "//article[@class='article']/div[@class='author-info-block']//div[@class='meta-box']/span/text()"));
            // 点赞量
            add(new ParseRule("likes", CrawlerEnum.ParseRuleType.XPATH, "//div[@class='panel-btn with-badge'][1]/@badge"));
            // 回复次数
            add(new ParseRule("commentCount", CrawlerEnum.ParseRuleType.XPATH, "//div[@class='panel-btn with-badge'][2]/@badge"));
            // 文章内容
            add(new ParseRule("content", CrawlerEnum.ParseRuleType.XPATH, "//article[@class='article']/html()"));
        }};
        return parseRules;
    }


    @Bean
    public CrawlerConfigProperty getZhihuConfigProperty() {
        Map<String, String> xpath = getXpath(CrawlerEnum.CrawlerType.ZHIHU);
        CrawlerConfigProperty property = new CrawlerConfigProperty();
        // 初始化url列表
        property.setInitCrawlerUrlList(getInitJuejinUrlList());
        // 初始化url解析规则定义
        property.setInitCrawlerXpath(xpath.get("initCrawlerXpath"));
        // 用户空间下的解析规则  url
        property.setHelpCrawlerXpath(xpath.get("helpCrawlerXpath"));
        // 抓取用户空间下的页大小
        property.setCrawlerHelpNextPagingSize(getCrawlerHelpNextPagingSize());
        // 目标页的解析规则
        property.setTargetParseRuleList(getZhihuTargetParseRuleList());
        return property;
    }


    /**
     * Zhihu 目标页的解析规则
     *
     * @return
     */
    private List<ParseRule> getZhihuTargetParseRuleList() {
        List<ParseRule> parseRules = new ArrayList<ParseRule>() {{
            // 标题
            add(new ParseRule("title", CrawlerEnum.ParseRuleType.XPATH, "//h1[@class='Post-Title']/text()"));
            // 作者
            add(new ParseRule("author", CrawlerEnum.ParseRuleType.XPATH, "//a[@class='UserLink-link']/text()"));
            // 发布日期
            add(new ParseRule("releaseDate", CrawlerEnum.ParseRuleType.XPATH, "//div[@class='ContentItem-time']/text()"));
            // 标签
            // add(new ParseRule("labels", CrawlerEnum.ParseRuleType.XPATH, "//div[@class='tag-list-container']/a/span//text()"));
            // 个人空间
            add(new ParseRule("personalSpace", CrawlerEnum.ParseRuleType.XPATH, "//span[@class='UserLink AuthorInfo-avatarWrapper']/a[@class='UserLink-link']/@href"));
            // 阅读量
            // add(new ParseRule("readCount", CrawlerEnum.ParseRuleType.XPATH, "//article[@class='article']/div[@class='author-info-block']//div[@class='meta-box']/span/text()"));
            // 点赞量
            add(new ParseRule("likes", CrawlerEnum.ParseRuleType.XPATH, "//button[@class='Button VoteButton VoteButton--up']/@aria-label"));
            // 回复次数
            add(new ParseRule("commentCount", CrawlerEnum.ParseRuleType.XPATH, "//button[@class='Button BottomActions-CommentBtn Button--plain Button--withIcon Button--withLabel']/text()"));
            // 文章内容
            add(new ParseRule("content", CrawlerEnum.ParseRuleType.XPATH, "//div[@class='Post-RichTextContainer']/html()"));
        }};
        return parseRules;
    }


    @Bean
    public CrawlerConfigProperty getWeixinConfigProperty() {
        Map<String, String> xpath = getXpath(CrawlerEnum.CrawlerType.WEIXIN);
        CrawlerConfigProperty property = new CrawlerConfigProperty();
        // 初始化url列表
        property.setInitCrawlerUrlList(getInitJuejinUrlList());
        // 初始化url解析规则定义
        property.setInitCrawlerXpath(xpath.get("initCrawlerXpath"));
        // 用户空间下的解析规则  url
        property.setHelpCrawlerXpath(xpath.get("helpCrawlerXpath"));
        // 抓取用户空间下的页大小
        property.setCrawlerHelpNextPagingSize(getCrawlerHelpNextPagingSize());
        // 目标页的解析规则
        property.setTargetParseRuleList(getWeixinTargetParseRuleList());
        return property;
    }


    /**
     * weixin 目标页的解析规则
     *
     * @return
     */
    private List<ParseRule> getWeixinTargetParseRuleList() {
        List<ParseRule> parseRules = new ArrayList<ParseRule>() {{
            // 标题
            add(new ParseRule("title", CrawlerEnum.ParseRuleType.XPATH, "//h1[@id='activity-name']/text()"));
            // 作者
            add(new ParseRule("author", CrawlerEnum.ParseRuleType.XPATH, "//a[@id='js_name']/text()"));
            // 发布日期
            add(new ParseRule("releaseDate", CrawlerEnum.ParseRuleType.XPATH, "//em[@id='publish_time']/text()"));
            // 标签
            // add(new ParseRule("labels", CrawlerEnum.ParseRuleType.XPATH, "//div[@class='tag-list-container']/a/span//text()"));
            // 个人空间
            // add(new ParseRule("personalSpace", CrawlerEnum.ParseRuleType.XPATH, "//div[@class='author-info-block']/a/@href"));
            // 阅读量
            // add(new ParseRule("readCount", CrawlerEnum.ParseRuleType.XPATH, "//article[@class='article']/div[@class='author-info-block']//div[@class='meta-box']/span/text()"));
            // 点赞量
            // add(new ParseRule("likes", CrawlerEnum.ParseRuleType.XPATH, "//div[@class='panel-btn with-badge'][1]/@badge"));
            // 回复次数
            // add(new ParseRule("commentCount", CrawlerEnum.ParseRuleType.XPATH, "//div[@class='panel-btn with-badge'][2]/@badge"));
            // 文章内容
            add(new ParseRule("content", CrawlerEnum.ParseRuleType.XPATH, "//div[@id='js_content']/html()"));
        }};
        return parseRules;
    }


    private Spider spider;

    public Spider getSpider() {
        return spider;
    }

    public void setSpider(Spider spider) {
        this.spider = spider;
    }


}
